using System.Linq.Expressions;
using Mapster;
using SqlSugar;
using Vin.Extension.Framework.Base;
using Vin.Extension.Framework.Dto;
using Vin.Extension.Framework.Entities;
using Vin.Extension.Framework.Extension;
using Vin.Extension.Framework.Interface;
using Vin.Extension.Framework.Repository;
using Vin.Extension.Redis.Cache;
using Vin.Tool.Attributes;

namespace Vin.Extension.Framework.Implement;

public class
    VinFrameworkBaseRecordServiceAsync<TEntityDto, TEntityListDto, TBaseRepository, TRepositoryEntity> :
    VinFrameworkBaseService,
    IVinFrameworkBaseServiceAsync<TEntityDto, TEntityListDto>
    where TEntityDto : VinFrameworkBaseEntityDto, new()
    where TEntityListDto : VinFrameworkBaseListDto, new()
    where TRepositoryEntity : VinFrameworkBaseRecordEntity, new()
    where TBaseRepository : class, IVinFrameworkBaseRecordRepository<TRepositoryEntity>
{
    [Inject] protected readonly TBaseRepository _baseRepository = null!;

    public TBaseRepository GetRepository() => _baseRepository;

    public virtual Expressionable<TRepositoryEntity> CreateExpressionable(
        Expression<Func<TRepositoryEntity, bool>>? expression = null)
    {
        return Expressionable.Create<TRepositoryEntity>()
            .AndIF(expression != null, expression);
    }

    public virtual Expressionable<T> CreateExpressionable<T>(
        Expression<Func<T, bool>>? expression = null) where T : VinFrameworkBaseRecordEntity, new()
    {
        return Expressionable.Create<T>()
            .AndIF(expression != null, expression);
    }

    public virtual async Task<List<T>> ListAsync<T>(TEntityListDto dto,
        Expressionable<TRepositoryEntity>? whereExpression = null, bool notPage = false)
    {
        var queryable = _baseRepository.AsQueryable();
        if (whereExpression != null)
        {
            queryable.Where(whereExpression.ToExpression());
        }

        return (await queryable.ToPageListRecordAsync(dto, notPage: notPage)).Adapt<List<T>>();
        // return queryable.ToPageListRecordAsync(dto, notPage: notPage);
        // var list = await _baseRepository.AsQueryable().ToPageListRecordAsync(dto, notPage: notPage);
        // return (await _baseRepository.AsQueryable()
        //     .WhereIF(whereExpression != null, whereExpression!.ToExpression())
        //     .ToPageListRecordAsync(dto, notPage: notPage)).Adapt<List<T>>();
    }

    public async Task<List<TEntityDto>> ListAsync(TEntityListDto dto,
        Expressionable<TRepositoryEntity> whereExpression)
    {
        return await ListAsync<TEntityDto>(dto, whereExpression);
    }

    public virtual async Task<List<TEntityDto>> ListAsync(TEntityListDto dto)
    {
        return await ListAsync<TEntityDto>(dto);
    }

    public virtual async Task<List<TEntityDto>> ListAllAsync(TEntityListDto? dto = null, bool checkEnabled = true)
    {
        return await ListAllAsync<TEntityDto>(dto ?? new TEntityListDto(), checkEnabled);
    }

    public virtual async Task<List<T>> ListAllAsync<T>(TEntityListDto dto, bool checkEnabled = true)
    {
        return await ListAllAsync<T>(CreateExpressionable(), checkEnabled);
    }

    public async Task<List<TEntityDto>> ListAllAsync(Expressionable<TRepositoryEntity> whereExpression,
        bool checkEnabled = true)
    {
        return await ListAllAsync<TEntityDto>(whereExpression, checkEnabled);
    }

    public async Task<List<T>> ListAllAsync<T>(Expressionable<TRepositoryEntity> whereExpression,
        bool checkEnabled = true)
    {
        whereExpression.AndIF(checkEnabled, m => m.IsEnabled == true);
        return await ListAsync<T>(new(), whereExpression, true);
    }

    public virtual async Task<T?> QueryAsync<T>(long id)
    {
        return (await _baseRepository.GetFirstAsync(m => m.Id == id)).Adapt<T?>();
    }

    public virtual async Task<TEntityDto?> QueryAsync(long id)
    {
        return (await _baseRepository.GetFirstAsync(m => m.Id == id))?.Adapt<TEntityDto>();
    }

    public virtual async Task<List<TEntityDto>> QueryByIdsAsync(List<long> ids)
    {
        return (await _baseRepository.QueryByIdsAsync(ids)).Adapt<List<TEntityDto>>();
    }

    public virtual async Task<TEntityDto?> SaveReturnDataAsync(TEntityDto dto)
    {
        return (await _baseRepository.SaveOrUpdateAsync(dto.Adapt<TRepositoryEntity>())).Adapt<TEntityDto>();
    }

    public async Task<TEntityDto?> SaveReturnDataAsync(TEntityDto dto, Func<TRepositoryEntity, Task>? insertCallback,
        Func<TRepositoryEntity, Task>? updateCallback = null)
    {
        return (await _baseRepository.SaveOrUpdateAsync(dto.Adapt<TRepositoryEntity>(), insertCallback, updateCallback))
            .Adapt<TEntityDto>();
    }

    public async Task<TEntityDto?> SaveReturnDataAsync(TEntityDto dto,
        Func<SaveType, TRepositoryEntity, Task> saveCallback)
    {
        return (await _baseRepository.SaveOrUpdateAsync(dto.Adapt<TRepositoryEntity>(), saveCallback))
            .Adapt<TEntityDto>();
    }

    public virtual async Task<bool> SaveAsync(TEntityDto dto)
    {
        return await SaveReturnDataAsync(dto) != null;
    }

    public virtual async Task<bool> DelAsync(long id)
    {
        return await _baseRepository.LogicDeleteAsync(m => m.Id == id);
    }

    public virtual async Task<bool> EnabledAsync(long id, bool? enabled)
    {
        if (!enabled.HasValue) return false;
        return await SaveAsync(new TEntityDto()
        {
            Id = id,
            IsEnabled = enabled,
        });
    }

    public virtual async Task<bool> EnabledAsync(long id)
    {
        return await _baseRepository.AsUpdateable().SetColumns(m => m.IsEnabled == !m.IsEnabled).Where(m => m.Id == id)
            .ExecuteCommandAsync() > 0;
    }

    public (List<TEntityDto>, List<TRepositoryEntity>, List<TRepositoryEntity>) Compare(
        List<TEntityDto> newDtoList, List<TRepositoryEntity> newList)
    {
        return _baseRepository.Compare(newDtoList, newList);
    }

    public (List<TRepositoryEntity>, List<TRepositoryEntity>, List<TRepositoryEntity>) Compare(
        List<TRepositoryEntity> newDtoList, List<TRepositoryEntity> newList)
    {
        return _baseRepository.Compare(newDtoList, newList);
    }
}